/**
 * MCU GPIO 驱动适配层头文件
 * Copyright (c) 2021 深圳市智辰科技有限公司
 * All rights reserved.
 */

#ifndef _GPIO_H_
#define _GPIO_H_

#include "stdc.h"
#include "std_type.h"
#include "std_err.h"

#ifdef __cplusplus
extern "C" {
#endif


/*
关于 PMU IRQ 的说明：
PMU_ISR_BIT_BAT			///< Battery full interrupt
PMU_ISR_BIT_ULV_PO		///< Ultra low power poweroff interrupt
PMU_ISR_BIT_LVD			///< Low voltage detected interrupt
PMU_ISR_BIT_OTP         ///< Over-temperature interrupt
PMU_ISR_BIT_ACOK		///< Charger plug in interrupt
PMU_ISR_BIT_CALI		///< Calibration: calibration done interrupt
PMU_ISR_BIT_ACOFF       ///< Charger pull off interrupt
PMU_ISR_BIT_ONKEY_PO    ///< Onkey_on/off: Onkey power on/off interrupt
PMU_ISR_BIT_ONKEY_HIGH  ///< 
PMU_ISR_BIT_ONKEY_LOW   ///< 
PMU_ISR_BIT_ADKEY0_LOW  ///< 
PMU_ISR_BIT_ADKEY0_HIGH ///< 
PMU_ISR_BIT_ADKEY1_LOW  ///< 
PMU_ISR_BIT_ADKEY1_HIGH ///< 
*/

/// GPIO 端口号定义
typedef enum {	
	GPIO_NUM_PA0 = 0,
	GPIO_NUM_PA1,
	GPIO_NUM_PA2,
	GPIO_NUM_PA3,
	GPIO_NUM_PA4,
	GPIO_NUM_PA5,
	GPIO_NUM_PA6,
	GPIO_NUM_PA7,
	
	GPIO_NUM_PB0,
	GPIO_NUM_PB1,
	GPIO_NUM_PB2,
	GPIO_NUM_PB3,
	GPIO_NUM_PB4,
	GPIO_NUM_PB5,
	GPIO_NUM_PB6,
	GPIO_NUM_PB7,
	
	GPIO_NUM_PC0,
	GPIO_NUM_PC1,
	GPIO_NUM_PC2,
	GPIO_NUM_PC3,
	GPIO_NUM_PC4,
	GPIO_NUM_PC5,
	GPIO_NUM_PC6,
	GPIO_NUM_PC7,
	
	GPIO_NUM_PD0,
	GPIO_NUM_PD1,
	GPIO_NUM_PD2,
	GPIO_NUM_PD3,
	GPIO_NUM_PD4,
	GPIO_NUM_PD5,
	GPIO_NUM_PD6,
	GPIO_NUM_PD7,
	
	GPIO_NUM_MAX
} gpio_num_t;

/// GPIO 由 CPU 还是 PMU 接管
typedef enum {
	GPIO_OWNER_CPU,
	GPIO_OWNER_PMU,
	GPIO_OWNER_MAX,
} gpio_owner_t;

/// GPIO 模式定义
typedef enum {
	GPIO_MODE_DISABLE = 0, // 禁用(默认上拉输入)
	GPIO_MODE_IN_PU   = 0, // 输入(上拉)
	GPIO_MODE_IN,          // 输入(不上拉)
	GPIO_MODE_OUT_PP,      // 输出(推挽)
	GPIO_MODE_OUT,         // 输出(无推挽)
	GPIO_MODE_MAX
} gpio_mode_t;

/// 外部中断触发类型
typedef enum {
    GPIO_INTR_LOW  = 0,		// GPIO interrupt type : input low level trigger
    GPIO_INTR_HIGH = 1,		// GPIO interrupt type : input high level trigger
    GPIO_INTR_POSEDGE = 2,	// GPIO interrupt type : rising edge
    GPIO_INTR_NEGEDGE = 3,	// GPIO interrupt type : falling edge
	GPIO_INTR_MAX
} gpio_intr_type_t;


/**
 * GPIO CPU 模式 API
 */
/// 端口配置(CPU 模式)
std_err_t GPIO_Config(gpio_num_t num, gpio_mode_t mode);
void GPIOS_Config(uint32_t pins, gpio_mode_t mode);
/// 设置输出电平(CPU 模式)
std_err_t GPIO_SetLevel(gpio_num_t num, uint8_t level);
void GPIOS_SetLevel(uint32_t pins, uint8_t level);
/// 获取输入电平(CPU 模式)
uint8_t GPIO_GetLevel(gpio_num_t num);
uint32_t GPIOS_GetLevel(uint32_t pins);
/// GPIO 双向通信(可以不用事先配置，而是在读写时再根据情况自动配置为OUT_PP/IN_PU)
uint8_t GPIO_BidiIn(gpio_num_t num);
std_err_t GPIO_BidiOut(gpio_num_t num, uint8_t level);

/// 使能中断(CPU 模式)
/// @param trig 触发类型
/// @param debounceUs 防抖时间(us): 0 ~ 25500 us
std_err_t GPIO_EXTI_Enable(gpio_num_t num, gpio_intr_type_t trig, uint16_t debounceUs);
void GPIOS_EXTI_Enable(uint32_t pins, gpio_intr_type_t trig, uint16_t debounceUs);
/// 关闭中断(CPU 模式)
std_err_t GPIO_EXTI_Disable(gpio_num_t num);
void GPIOS_EXTI_Disable(uint32_t pins, gpio_num_t num);
/// 翻转中断触发(边沿/电平)极性(CPU 模式)
/// !!! 注意：由于 FR801xH 不能设置为任意沿，所以需要手动切换触发边沿/电平 !!!
std_err_t GPIO_EXTI_ToggleTrigLevel(gpio_num_t num);
/// 判断 GPIO 口是否产生 EXTI 中断(CPU 模式)
uint8_t GPIO_EXTI_Flag(gpio_num_t num);
/// 清除 GPIO 口对应的 EXTI 中断标志位(CPU 模式)
std_err_t GPIO_EXTI_Clear(gpio_num_t num);

/// GPIO 端口配置为 PWM 输出(CPU 模式)
std_err_t GPIO_ConfigAsPwm(gpio_num_t num, uint32_t freq, uint32_t duty);
/// 设置 PWM 占空比(0.01%)
std_err_t GPIO_PwmSetDuty(gpio_num_t num, uint32_t duty);
/// 获取 PWM 占空比(0.01%)
uint32_t       GPIO_PwmGetDuty(gpio_num_t num);
/// 启动 PWM 输出
std_err_t GPIO_PwmStart(gpio_num_t num);
/// 停止 PWM 输出
std_err_t GPIO_PwmStop(gpio_num_t num);

/**
 * GPIO PMU 模式 API
 */
/// GPIO 端口配置(PMU 模式)
std_err_t GPIO_PMU_Config(gpio_num_t num, gpio_mode_t mode);
void GPIOS_PMU_Config(uint32_t pins, gpio_mode_t mode);
/// 设置输出电平(CPU 模式)
std_err_t GPIO_PMU_SetLevel(gpio_num_t num, uint8_t level);
void GPIOS_PMU_SetLevel(uint32_t pins, uint8_t level);
/// 获取输入电平(CPU 模式)
uint8_t GPIO_PMU_GetLevel(gpio_num_t num);
uint32_t GPIOS_PMU_GetLevel(uint32_t pins);

/// GPIO 端口配置为可唤醒(PMU 模式)
std_err_t GPIO_PMU_EnableWakeup(gpio_num_t num);
void GPIOS_PMU_EnableWakeup(uint32_t pins);
/// GPIO 端口配置为不可唤醒(PMU 模式)
std_err_t GPIO_PMU_DisableWakeup(gpio_num_t num);
void GPIOS_PMU_DisableWakeup(uint32_t pins);

/**
 * GPIO APIs 函数类型声明
 */
typedef std_err_t (*FUNC_GPIO_Config)(gpio_mode_t mode);
typedef uint8_t        (*FUNC_GPIO_ReadIn)(void);
typedef std_err_t (*FUNC_GPIO_Out)(uint8_t x);
typedef uint8_t        (*FUNC_GPIO_ReadOut)(void);
typedef std_err_t (*FUNC_GPIO_Toggle)(void);
typedef std_err_t (*FUNC_GPIO_EXTI_Enable)(gpio_intr_type_t trig, uint16_t debounceUs);
typedef std_err_t (*FUNC_GPIO_EXTI_ToggleTrigLevel)(void);
typedef std_err_t (*FUNC_GPIO_EXTI_Disable)(void);
typedef uint8_t        (*FUNC_GPIO_EXTI_Flag)(void);
typedef uint8_t        (*FUNC_GPIO_EXTI_Clear)(void);

typedef std_err_t (*FUNC_GPIO_On)(void);
typedef std_err_t (*FUNC_GPIO_Off)(void);
typedef std_err_t (*FUNC_GPIO_Switch)(uint8_t on);
typedef uint8_t        (*FUNC_GPIO_IsInOn)(void);
typedef uint8_t        (*FUNC_GPIO_IsInOff)(void);
typedef uint8_t        (*FUNC_GPIO_IsOutOn)(void);
typedef uint8_t        (*FUNC_GPIO_IsOutOff)(void);
typedef uint8_t        (*FUNC_GPIO_Polarity)(void);

typedef std_err_t (*FUNC_GPIO_ConfigAsPwm)(uint32_t freq, uint32_t duty);
typedef std_err_t (*FUNC_GPIO_PwmSetDuty)(uint32_t duty);
typedef uint32_t       (*FUNC_GPIO_PwmGetDuty)();
typedef std_err_t (*FUNC_GPIO_PwmStart)();
typedef std_err_t (*FUNC_GPIO_PwmStop)();

/**
 * 定义命名的 GPIO APIs(基本的)
 */
#define GPIO_DEFINE(NAME, PIN) \
	static const gpio_num_t GPIO_##NAME##_Num                        = GPIO_NUM_##PIN; \
	static const uint32_t        GPIO_##NAME##_Bit                        = 1UL << GPIO_NUM_##PIN; \
	inline static std_err_t GPIO_##NAME##_Config(gpio_mode_t mode)   { return GPIO_Config(GPIO_NUM_##PIN, mode); } \
	inline static uint8_t        GPIO_##NAME##_ReadIn(void)               { return GPIO_GetLevel(GPIO_NUM_##PIN); } \
	inline static std_err_t GPIO_##NAME##_Out(uint8_t x)                  { return GPIO_SetLevel(GPIO_NUM_##PIN, x); } \
	inline static uint8_t        GPIO_##NAME##_ReadOut(void)              { return GPIO_GetLevel(GPIO_NUM_##PIN); } \
	inline static uint8_t        GPIO_##NAME##_BidiIn(void)               { return GPIO_BidiIn(GPIO_NUM_##PIN); } \
	inline static std_err_t GPIO_##NAME##_BidiOut(uint8_t x)              { return GPIO_BidiOut(GPIO_NUM_##PIN, x); } \
	inline static std_err_t GPIO_##NAME##_Toggle(void)               { return GPIO_SetLevel(GPIO_NUM_##PIN, !GPIO_GetLevel(GPIO_NUM_##PIN)); } \
	inline static std_err_t GPIO_##NAME##_EXTI_Enable(gpio_intr_type_t trig, uint16_t debounceUs) { return GPIO_EXTI_Enable(GPIO_NUM_##PIN, trig, debounceUs); } \
	inline static std_err_t GPIO_##NAME##_EXTI_ToggleTrigLevel(void) { return GPIO_EXTI_ToggleTrigLevel(GPIO_NUM_##PIN); } \
	inline static std_err_t GPIO_##NAME##_EXTI_Disable(void)         { return GPIO_EXTI_Disable(GPIO_NUM_##PIN); } \
	inline static std_err_t GPIO_##NAME##_EXTI_Flag(void)            { return GPIO_EXTI_Flag(GPIO_NUM_##PIN); } \
	inline static std_err_t GPIO_##NAME##_EXTI_Clear(void)           { return GPIO_EXTI_Clear(GPIO_NUM_##PIN); } \
	inline static std_err_t GPIO_##NAME##_PmuConfig(gpio_mode_t mode){ return GPIO_PMU_Config(GPIO_NUM_##PIN, mode); } \
	inline static uint8_t        GPIO_##NAME##_PmuReadIn(void)            { return GPIO_PMU_GetLevel(GPIO_NUM_##PIN); } \
	inline static std_err_t GPIO_##NAME##_PmuOut(uint8_t x)               { return GPIO_PMU_SetLevel(GPIO_NUM_##PIN, x); } \
	inline static std_err_t GPIO_##NAME##_PmuToggle(void)            { return GPIO_PMU_SetLevel(GPIO_NUM_##PIN, !GPIO_PMU_GetLevel(GPIO_NUM_##PIN)); } \
	inline static std_err_t GPIO_##NAME##_PmuEnableWakeup(void)      { return GPIO_PMU_EnableWakeup(GPIO_NUM_##PIN); } \
	inline static std_err_t GPIO_##NAME##_PmuDisableWakeup(void)     { return GPIO_PMU_DisableWakeup(GPIO_NUM_##PIN); }

/**
 * 定义命名的 GPIO APIs(带极性的)
 */
#define GPIO_DEFINE_POLARITY(NAME, PIN, ACTIVE_LEVEL) \
	GPIO_DEFINE(NAME, PIN) \
	inline static uint8_t        GPIO_##NAME##_Polarity(void)             { return ACTIVE_LEVEL; } \
	inline static std_err_t GPIO_##NAME##_On(void)                   { return GPIO_##NAME##_Out(ACTIVE_LEVEL); } \
	inline static std_err_t GPIO_##NAME##_Off(void)                  { return GPIO_##NAME##_Out(!ACTIVE_LEVEL); } \
	inline static std_err_t GPIO_##NAME##_Switch(uint8_t on)              { return on ? GPIO_##NAME##_Out(ACTIVE_LEVEL) : GPIO_##NAME##_Out(!ACTIVE_LEVEL); } \
	inline static uint8_t        GPIO_##NAME##_IsInOn(void)               { return (GPIO_##NAME##_ReadIn() == ACTIVE_LEVEL); } \
	inline static uint8_t        GPIO_##NAME##_IsInOff(void)              { return (GPIO_##NAME##_ReadIn() != ACTIVE_LEVEL); } \
	inline static uint8_t        GPIO_##NAME##_IsOutOn(void)              { return (GPIO_##NAME##_ReadOut() == ACTIVE_LEVEL); } \
	inline static uint8_t        GPIO_##NAME##_IsOutOff(void)             { return (GPIO_##NAME##_ReadOut() != ACTIVE_LEVEL); } \
	inline static std_err_t GPIO_##NAME##_PmuOn(void)                { return GPIO_##NAME##_PmuOut(ACTIVE_LEVEL); } \
	inline static std_err_t GPIO_##NAME##_PmuOff(void)               { return GPIO_##NAME##_PmuOut(!ACTIVE_LEVEL); } \
	inline static std_err_t GPIO_##NAME##_PmuSwitch(uint8_t on)           { return on ? GPIO_##NAME##_PmuOut(ACTIVE_LEVEL) : GPIO_##NAME##_PmuOut(!ACTIVE_LEVEL); } \
	inline static uint8_t        GPIO_##NAME##_PmuIsInOn(void)            { return (GPIO_##NAME##_PmuReadIn() == ACTIVE_LEVEL); } \
	inline static uint8_t        GPIO_##NAME##_PmuIsInOff(void)           { return (GPIO_##NAME##_PmuReadIn() != ACTIVE_LEVEL); } \
	inline static std_err_t GPIO_##NAME##_ConfigAsPwm(uint32_t freq, uint32_t duty) { return GPIO_ConfigAsPwm(GPIO_NUM_##PIN, freq, ACTIVE_LEVEL ? duty : (10000-duty)); } \
	inline static std_err_t GPIO_##NAME##_PwmSetDuty(uint32_t duty)       { return GPIO_PwmSetDuty(GPIO_NUM_##PIN, ACTIVE_LEVEL ? duty : (10000-duty)); } \
	inline static uint32_t       GPIO_##NAME##_PwmGetDuty(void)           { uint32_t duty = GPIO_PwmGetDuty(GPIO_NUM_##PIN); return ACTIVE_LEVEL ? duty : (10000-duty); } \
	inline static std_err_t GPIO_##NAME##_PwmStart(void)             { return GPIO_PwmStart(GPIO_NUM_##PIN); } \
	inline static std_err_t GPIO_##NAME##_PwmStop(void)              { return GPIO_PwmStop(GPIO_NUM_##PIN); }

/**
 * LED1/LED2 引脚特殊情况单独定义(不支持输入)
 */
// 设置 LED1 引脚电平
std_err_t gpio_led1_set_level(uint8_t level);
// 读取 LED1 引脚当前输出的电平
uint8_t gpio_led1_get_level(void);
	
#define LED1PIN_DEFINE(NAME) \
	inline static std_err_t GPIO_##NAME##_Out(uint8_t x)      { return gpio_led1_set_level(x); } \
	inline static std_err_t GPIO_##NAME##_ReadOut(void)  { return gpio_led1_get_level(); } \
	inline static std_err_t GPIO_##NAME##_Toggle(void)   { return gpio_led1_set_level(!gpio_led1_get_level()); }

#define LED1PIN_DEFINE_POLARITY(NAME, ACTIVE_LEVEL) \
	LED1PIN_DEFINE(NAME) \
	inline static std_err_t GPIO_##NAME##_On(void)       { return GPIO_##NAME##_Out(ACTIVE_LEVEL); } \
	inline static std_err_t GPIO_##NAME##_Off(void)      { return GPIO_##NAME##_Out(!ACTIVE_LEVEL); } \
	inline static std_err_t GPIO_##NAME##_Switch(uint8_t on)  { return on ? GPIO_##NAME##_Out(ACTIVE_LEVEL) : GPIO_##NAME##_Out(!ACTIVE_LEVEL); } \
	inline static uint8_t        GPIO_##NAME##_IsOutOn(void)  { return (GPIO_##NAME##_ReadOut() == ACTIVE_LEVEL); } \
	inline static uint8_t        GPIO_##NAME##_IsOutOff(void) { return (GPIO_##NAME##_ReadOut() != ACTIVE_LEVEL); } \
	inline static uint8_t        GPIO_##NAME##_Polarity(void) { return ACTIVE_LEVEL; }

// 设置 LED2 引脚电平
std_err_t gpio_led2_set_level(uint8_t level);
// 读取 LED2 引脚当前输出的电平
uint8_t gpio_led2_get_level(void);
	
#define LED2PIN_DEFINE(NAME) \
	inline static std_err_t GPIO_##NAME##_Out(uint8_t x)      { return gpio_led2_set_level(x); } \
	inline static std_err_t GPIO_##NAME##_ReadOut(void)  { return gpio_led2_get_level(); } \
	inline static std_err_t GPIO_##NAME##_Toggle(void)   { return gpio_led2_set_level(!gpio_led2_get_level()); }

#define LED2PIN_DEFINE_POLARITY(NAME, ACTIVE_LEVEL) \
	LED2PIN_DEFINE(NAME) \
	inline static std_err_t GPIO_##NAME##_On(void)       { return GPIO_##NAME##_Out(ACTIVE_LEVEL); } \
	inline static std_err_t GPIO_##NAME##_Off(void)      { return GPIO_##NAME##_Out(!ACTIVE_LEVEL); } \
	inline static std_err_t GPIO_##NAME##_Switch(uint8_t on)  { return on ? GPIO_##NAME##_Out(ACTIVE_LEVEL) : GPIO_##NAME##_Out(!ACTIVE_LEVEL); } \
	inline static uint8_t        GPIO_##NAME##_IsOutOn(void)  { return (GPIO_##NAME##_ReadOut() == ACTIVE_LEVEL); } \
	inline static uint8_t        GPIO_##NAME##_IsOutOff(void) { return (GPIO_##NAME##_ReadOut() != ACTIVE_LEVEL); } \
	inline static uint8_t        GPIO_##NAME##_Polarity(void) { return ACTIVE_LEVEL; }

	
#ifdef __cplusplus
}
#endif

#endif // _GPIO_H_
